package com.longcai.cm.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import com.longcai.cm.base.service.BaseServiceImpl;
import com.longcai.cm.common.utils.StringUtil;
import com.longcai.cm.common.utils.StringUtils;
import com.longcai.cm.dao.*;
import com.longcai.cm.domain.*;
import com.longcai.cm.domain.vm.MemberVipViewModel;
import com.longcai.cm.exception.SysRuntimeException;
import com.longcai.cm.moudules.system.bean.DicCode;
import com.longcai.cm.moudules.system.domain.SysDicValue;
import com.longcai.cm.moudules.system.service.SysDicCodeService;
import com.longcai.cm.pay.ali.AliPayApi;
import com.longcai.cm.pay.wx.WxPayApp;
import com.longcai.cm.pay.wx.domain.WxRefundParam;
import com.longcai.cm.service.JaMemberAssetService;
import com.longcai.cm.service.JaMemberCouponsService;
import com.longcai.cm.service.JaMemberVipService;
import com.longcai.cm.service.JaOrderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Optional;


/**
 * @author LBX
 */
@Service
public class JaOrderServiceImpl extends BaseServiceImpl<JaOrder> implements JaOrderService {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Resource
    private JaGoodsInfoMapper goodsInfoMapper;

    @Resource
    private JaGoodsCouponMapper goodsCouponMapper;

    @Resource
    private JaCouponMapper couponMapper;

    @Resource
    private JaVipInfoMapper vipInfoMapper;

    @Resource
    private JaMemberAssetService memberAssetService;

    @Resource
    private JaMemberVipService memberVipService;

    @Resource
    private JaMemberCouponsService memberCouponsService;

    @Resource
    private JaShopMapper shopMapper;

    @Resource
    private SysDicCodeService sysDicCodeService;

    /**
     * 创建订单
     *
     * @param order    订单信息
     * @param memberId 用户id
     * @param isVip    是否会员
     * @return 订单
     */
    @Override
    public JaOrder createOrder(JaOrder order, Integer memberId, Boolean isVip) {
//        基础属性
        order.setCreateTime(DateUtil.now());
        order.setMemberId(memberId);
        order.setOrderStatus(0);
//        订单类型 1团购 2秒杀 3团券 4会员
        switch (order.getOrderType()) {
            case 1:
                order.setOrderNum(StringUtil.getOrderNum("T"));
                normalGoodInfo(order, isVip);
                break;
            case 2:
                order.setOrderNum(StringUtil.getOrderNum("S"));
                normalGoodInfo(order, isVip);
                break;
            case 3:
                order.setOrderNum(StringUtil.getOrderNum("C"));
                couponGoodInfo(order);
                break;
            case 4:
                order.setOrderNum(StringUtil.getOrderNum("V"));
                vipGoodInfo(order);
                break;
            default:
                throw new SysRuntimeException("订单类型错误");
        }
//        最终价格 附：reduceAmount（优惠券+积分 抵扣总额）
        order.setPayAmount(order.getOrderAmount().subtract(order.getReduceAmount()).max(new BigDecimal("0.01")));
        save(order);
        return order;
    }

    private void normalGoodInfo(JaOrder order, Boolean isVip) {
//        商品属性
        final JaGoodsInfo good = goodsInfoMapper.selectById(order.getGoodId());
        order.setGoodName(good.getGoodName());
        order.setGoodImg(good.getCoverImg());
        order.setExpireTime(DateUtil.date().offset(DateField.DAY_OF_YEAR, good.getEffectiveDuration()).toString());
        if (order.getOrderType() == 1) {
            if (isVip) {
//            会员价
                order.setOrderAmount(good.getVipPrice());
            } else {
//            正常价
                order.setOrderAmount(good.getSalePrice());
            }
        } else {
            order.setOrderAmount(good.getSalePrice());
        }
    }

    private void couponGoodInfo(JaOrder order) {
//        商品属性
        final JaGoodsCoupon good = goodsCouponMapper.selectById(order.getGoodId());
        if (good.getCouponLeftCount() < 1) {
            throw new SysRuntimeException("库存不足");
        }
        final JaOrder one = lambdaQuery().eq(JaOrder::getOrderStatus, 1).eq(JaOrder::getGoodId, good.getId()).eq(JaOrder::getMemberId, order.getMemberId()).one();
        if (one != null) {
            throw new SysRuntimeException("每人仅可购买一次");
        }
        order.setGoodName(good.getGoodName());
        order.setGoodImg(good.getGoodImg());
        order.setGoodId(good.getId());
        final JaCoupon coupon = couponMapper.selectById(good.getCouponId());
        order.setExpireTime(DateUtil.date().offset(DateField.DAY_OF_YEAR, coupon.getEffectiveDays()).toString());
//            正常价
        order.setOrderAmount(good.getSalePrice());
    }

    private void vipGoodInfo(JaOrder order) {
//        商品属性
        final JaVipInfo good = vipInfoMapper.selectById(order.getGoodId());

        if (good.getLevel() == 1) {
            long count = lambdaQuery()
                    .eq(JaOrder::getGoodId, good.getId())
                    .eq(JaOrder::getOrderStatus, 1)
                    .eq(JaOrder::getMemberId, order.getMemberId()).count();
            if (count >= good.getLimitCount()) {
                throw new SysRuntimeException("该产品为限购产品，当前试用次数不足");
            }
        }

        order.setGoodName(good.getName());
        order.setGoodId(good.getId());
        order.setExpireTime(DateUtil.date().offset(DateField.DAY_OF_YEAR, good.getAvailableMonth()).toString());
//            正常价
        order.setOrderAmount(good.getAmount());
    }

    /**
     * 交易完成 订单核验
     *
     * @param orderId   订单id
     * @param tradeNo   三方交易号
     * @param payAmount 实付金额
     * @param payType   支付类型
     */
    @Override
    public void tradeFinish(String orderId, String tradeNo, BigDecimal payAmount, int payType) {
        logger.info(orderId + "更新订单状态");
        JaOrder order = lambdaQuery()
                .eq(JaOrder::getId, orderId)
                .one();
        if (order.getOrderStatus() == 1) {
//        已处理过 跳过
            return;
        }
        order.setPayAmount(payAmount);
        order.setPayTime(DateUtil.now());
        order.setPayType(payType);
//        订单状态 0待支付 1待使用 2待评价 3已完成 4已取消 5退款
        order.setOrderStatus(1);
        order.setTransitionId(tradeNo);

//        购买内容兑现
        convertTransition(order);

//        更新订单
        updateById(order);
    }

    private void convertTransition(JaOrder order) {
        String shopId = order.getShopId();
        switch (order.getOrderType()) {
            case 1:
            case 2:
//                团购秒杀
                final Long count = lambdaQuery().eq(JaOrder::getGoodId, order.getGoodId()).count();
                JaGoodsInfo goodsInfo = new JaGoodsInfo();
                goodsInfo.setId(order.getGoodId());
                goodsInfo.setSaleCount(Math.toIntExact(count));
                goodsInfoMapper.updateById(goodsInfo);
                System.err.println("这个不用不发货");
                break;
            case 3:
//                团券
                final JaGoodsCoupon good = goodsCouponMapper.selectById(order.getGoodId());
                good.setSaleCount(good.getSaleCount() + 1);
                good.setCouponLeftCount(good.getCouponLeftCount() - 1);
                if (good.getCouponLeftCount() == 0) {
                    good.setStatus(0);
                }
                goodsCouponMapper.updateById(good);
                memberCouponsService.addCoupons(good.getCouponId(), good.getCouponCount(), order.getMemberId());
                break;
            case 4:
//                VIP
                memberVipService.addVip(order.getGoodId(), order.getMemberId());
                order.setOrderProfit(order.getPayAmount());
                order.setOrderPayable(new BigDecimal(0));
                break;
            default:
                break;
        }
        if (StringUtils.isNotBlank(shopId)) {
            logger.info("门店销量核算");
            final Long count = lambdaQuery().eq(JaOrder::getShopId, shopId)
                    .count();
            JaShop shop = new JaShop();
            shop.setId(shopId);
            shop.setCount(count);
            shopMapper.updateById(shop);
        }
    }

    /**
     * @param orderId 订单id
     * @param member  用户id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void checkOrder(String orderId, FaMember member) {
        final JaOrder order = getById(orderId);
        if (DateUtil.parse(order.getExpireTime()).before(DateUtil.date())) {
            refundOrder(order.getPayAmount(), order.getPayAmount(), order.getOrderNum(), order.getPayType());
            order.setOrderStatus(3);
            updateById(order);
            throw new SysRuntimeException("商品已过有效期, 已自动退款");
        }
        if (order.getOrderStatus() != 1) {
            throw new SysRuntimeException("订单状态已更新 请检查后重试");
        }
        if (!member.getShopId().equals(order.getShopId())) {
            throw new SysRuntimeException("门店不符合");
        }
        order.setUseTime(DateUtil.now());
        order.setOrderStatus(2);
        order.setCheckUserId(member.getId());
        order.setCheckUsername(member.getName());

        final JaGoodsInfo goodsInfo = goodsInfoMapper.selectById(order.getGoodId());
        if (goodsInfo == null) {
            throw new SysRuntimeException("商品信息缺失");
        }
        final BigDecimal payAmount = order.getPayAmount();
//        费率
        final BigDecimal commissionRate = goodsInfo.getCommissionRate();
        order.setOrderProfit(payAmount.multiply(commissionRate));
//        查询三方支付费率
        final List<SysDicValue> payTaxList = sysDicCodeService.getListByCode(DicCode.PAY_TAX);
        final Optional<SysDicValue> first = payTaxList.stream().filter(f -> order.getPayType().toString().equals(f.getCode())).findFirst();
        if (first.isPresent()) {
//            订单应付(计算方式：订单实际支付金额 - 平台佣金 - 手续费（微信支付宝）)
            final SysDicValue dicValue = first.get();
            final BigDecimal payTax = new BigDecimal(dicValue.getValue()).multiply(payAmount);
            order.setOrderPayable(payAmount.subtract(order.getOrderProfit()).subtract(payTax));
        }

        //                下单积分奖励
        final BigDecimal ratio = new BigDecimal(sysDicCodeService.getTextValueByCode(DicCode.CREATE_ORDER_INTEGRAL));
        memberAssetService.updateMemberAssetIntegral(order.getMemberId() + "", order.getPayAmount().multiply(ratio).setScale(0, RoundingMode.HALF_UP), 1, order.getShopName() + order.getGoodName() + ",下单积分奖励");

        updateById(order);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String refundOrder(BigDecimal refundAmount, BigDecimal totalAmount, String orderNum, Integer payType) {
        if (refundAmount.doubleValue() > totalAmount.doubleValue()) {
            throw new SysRuntimeException("退款金额不能大于订单金额");
        }
        if (refundAmount.doubleValue() <= 0) {
            return "";
        }
//        支付类型 1微信App 2支付宝 3微信小程序 4钱包支付
        WxRefundParam param = new WxRefundParam();
        param.setOrderNum(orderNum);
        param.setTotal(totalAmount);
        param.setRefund(refundAmount);
        param.setRefundId(orderNum.replace(orderNum.substring(0, 1), "R"));
        switch (payType) {
            case 1:
                return WxPayApp.orderRefundApp(param);
            case 2:
                try {
                    return AliPayApi.refundOrderAliPay(param);
                } catch (Exception e) {
                    throw new SysRuntimeException("支付宝退款失败");
                }
            default:
                return "";
        }
    }
}
